﻿using System;
using System.IO;

namespace Dwarf.Managed
{
    /// <summary>Class for command line settings processing, IO management</summary>
    /// 
    public class Configurator
    {
        private Settings settings;
        private StreamWriter profileWriter;
        private const int infinity = int.MaxValue;
        private String dwarfName;

        /// <summary>Cli parameters initialization</summary>
        /// <param name="args">Command line parameters</param>
        /// 
        public Configurator(string[] args, String name)
        {
            dwarfName = name;
            settings = new Settings();
            settings.GetSettings(args);
            if (settings.profileFile != "")
            {
                profileWriter = new StreamWriter(new FileStream(settings.profileFile, FileMode.Create, FileAccess.Write, FileShare.Write));
            }
        }

        /// <summary>Write settings</summary>
        ///
        public void WriteSettings()
        {
            String stringSettings = settings.StringSettings();
            Console.WriteLine(stringSettings);               // write to console
        }

        /// <summary>Close the profile and result files</summary>
        /// <param name="time">Execution time</param>
        /// <param name="cities">Solution graph edges</param>
        /// <param name="cityCount">Cities matrix dimension</param>
        ///
        public void Close(double time, int[] cities, int cityCount)
        {
            String timeResult = time.ToString("F8");
            Console.WriteLine("Clock time    (sec) : " + timeResult);
            if (profileWriter != null)                      // write to profile file
            {
                profileWriter.WriteLine("#Dwarfname:{0}", dwarfName);
                profileWriter.WriteLine("#Time: {0}", DateTime.Now.ToString());
                profileWriter.WriteLine("#Dimensions: 2");
                profileWriter.WriteLine("#Matrix Size: {0}", cityCount);
                profileWriter.WriteLine("#Result time (sec): {0}", timeResult);
                profileWriter.WriteLine("#eof");
                profileWriter.Close();
            }

            if (settings.resultFile != "")                  // write to outputfile
            {
                StreamWriter resultWriter = new StreamWriter(new FileStream(settings.resultFile, FileMode.Create, FileAccess.Write, FileShare.Write));
                for (int i = 0; i < cityCount; i++)
                {
                    resultWriter.WriteLine("Edge: (" + i + ";" + cities[i] + ")");
                }
                resultWriter.Close();
            }
        }

        /// <summary>Convert char of input string to digit and add to 'value'</summary>
        /// <param name="value">Result of adding</param>
        /// <param name="source">New char of source string</param>
        ///
        private void AddNextChar(ref int value, char source)
        {
            value = value * 10 + ((int)source - (int)'0');  // digit transformation
        }

        /// <summary>Get cityCount and fill distances[cityCount, cityCount] matrix</summary>
        /// <param name="cityCount">Dimension of cities matrix</param>
        /// <param name="dictances">Cities matrix</param>
        ///
        public void GetData(ref int cityCount, ref int[,] distances)
        {
            // Open the file to read from.
            FileStream stream = null;
            StreamReader reader = null;
            try
            {
                stream = new FileStream(settings.inputFile, FileMode.Open, FileAccess.Read, FileShare.Read);
                reader = new StreamReader(stream);
                string stringCount = reader.ReadLine();         // read the first line containing the cities count
                for (int i = 0; i < stringCount.Length; i++)
                {
                    AddNextChar(ref cityCount, stringCount[i]); // convert from string to int
                }
                // cityCount++;                                    // add subsidiary row / column for storing the sequence number () of cell's dimension correspondiong the source array

                distances = new int[cityCount, cityCount];      // initialize the array of distances

                //for (int i = 0; i < cityCount; i++)
                //{
                //    distances[0, i] = distances[i, 0] = i;      // add source indexes to zero's row and column
                //}

                for (int i = 0; i < cityCount; i++)             // fill the array
                {
                    int position = 0;                           // initialize the counter of tokens of current string                          
                    stringCount = reader.ReadLine();            // current distances string
                    for (int j = 0; j < stringCount.Length; j++)
                    {
                        char currentChar = stringCount[j];
                        if (currentChar == ' ')                 // condition of a new token start
                        {
                            position++;                         // change the array index
                        }
                        else
                        {                                       // convert from current token to int and put to the corresponding array cell
                            if (currentChar == '-')             // edges where threre are no way (distance is equal to infinity)
                            {
                                distances[i, position] = infinity;
                            }
                            else
                            {
                                AddNextChar(ref distances[i, position], currentChar);
                            }
                        }
                    }
                }
                for (int i = 1; i < cityCount; i++)             // for the exception cases (de bene esse) we override the distances from point to the same to be equal infinity
                {
                    distances[i, i] = infinity;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Cannot correctly read the file: {0}", e.Message);
            }
            reader.Close();
        }

        /// <summary>Print the array</summary>
        /// <param name="currentDistances">Matrix to be printed</param>
        /// <param name="dimensionLength">Dimension of the square matrix currentDistances</param>
        ///
        public void PrintArray(ref int[,] currentDistances, int dimensionLength)
        {
            String trace = "\nIteration";
            for (int i = 1; i < dimensionLength; i++)
            {
                for (int j = 1; j < dimensionLength; j++)
                {
                    int value = currentDistances[i, j];
                    if (value == infinity)
                    {
                        trace += "- ";
                    }
                    else
                    {
                        trace += value + " ";
                    }
                }
                trace += "\n";
            }
            Console.WriteLine(trace);
            //if (profileWriter != null)                   // write to profile file
            //{
            //    profileWriter.WriteLine(trace);
            //}
        }
    }
}